package gfdclient;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.*;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

/**
 * Класс инкапсулирующий настройки пользователя в XML файл, и предоставляющий
 * интуитивно понятный интерфейс для работы со свойствами пользователя
 * @author Volk ID = 1001
 */
public class ConfigurateFile {
  //--------------------Аттрибуты класса-----------------------------------
  Document document; //Объект инкапсулирующий XML-документ
  String path; //Путь к XML-файлу
  final String fileName = "UserOption.xml"; //Имя файла свойств
  final String USER = "User"; //Тег элемента "User";
    final String NAME = "name"; //Тег аттрибута "name" элемента "User"
    final String PASSWORD = "password"; //Тег аттрибута "password" элемента "User"
  final String SERVER = "Server"; //Тип элмемента "Server"
    final String HOST = "host"; //Тег аттрибута "host" элемента "User"

  //-----------------------------------------------------------------------

  //--------------------Сервисные методы-----------------------------------

  /**
   * Найти пользователя по имени
   * @param name - имя пользователя
   * @return пользовательский XML-элемент, null - настроек пользователя нет в файле
  */
  private Element findUser(String name){
    if(name == null) throw new NullPointerException();
    //Получит корень
    Element root = document.getDocumentElement();
    //Получить всех юзеров мнформация о которых присутствует в файлах настроек
    NodeList userList = root.getChildNodes();
    //Пройтись по всем пользователям получив аттрибут имя пользователя и сравнив его со входным
    for(int i = 0; i < userList.getLength(); i++){
    //Разбор производится без учёта разделителей
     if(userList.item(i) instanceof Element){
      //Здесь происходит получение аттрибута "name" и сравнение его со входным именем
      Element temp = (Element)userList.item(i);
      String nameValue = temp.getAttribute(NAME);
      if(nameValue.equals(name)) return temp;
     }
    }
    return null;
  }

  /**
   * Определить присутствует ли сервер с заданным именем
   * @param user - пользователь в списке серверов которого необходимо организовать поиск
   * @param serverName - имя сервера
   * @return true - сервер найдён, false - сервер не найден
   */
  private boolean findServer(Element user, String serverName){
    if(getServer(user,serverName) == null) return false;
     return true;
  }


  private Element getServer(Element user, String serverName){
     NodeList serverList = user.getChildNodes();
     Element server;
     for(int i = 0; i < serverList.getLength(); i++){
      if(serverList.item(i) instanceof Element){
        server = (Element)serverList.item(i);
        String host = server.getAttribute(HOST);
        if(host.equals(serverName)) return server;
      }
     }
     return null;
  }

  //-----------------------------------------------------------------------

  //--------------------Интерфейсные методы--------------------------------
  /**
   * Конструктор, в котором происходит инициализация файла настроек
   * @throws javax.xml.parsers.ParserConfigurationException в случае если невозможно создать файл настроек
   */
  public ConfigurateFile(String path) throws ParserConfigurationException{
   if(path == null) path = "";
    else this.path = path;
   //---------Ночь, устал, всё что осталось сделать поставить заплатку----
   try{
    Import();
   }catch(Exception e){
       //---------------------------------------------------------------------
       //Создать фабрику XML- использующую при разборе DOM-модель
       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
       //Создать построитель XML-документа
       DocumentBuilder builder;
       builder = factory.newDocumentBuilder(); //Вот эта штука генерит исключение ParserConfigurationException
       //Создать XML-документ
       document = builder.newDocument();
       //Создать корневой элемент configuration
       Element root = document.createElement("configuration");
       //Добавить корневой элемент к XML-документу
       document.appendChild(root);
   }
  }

  /**
   * Проверить, существуют ли настройки для пользователя с указанной записью
   * @param name - имя пользователя
   * @return true - настройки существуют, false - настроек пользователя нет в файле
   */
  public boolean isUser(String name){
   if(findUser(name) == null) return false;
    else return true;
  }

  /**
   * Добавить настройки пользователя
   * @param name - имя пользователя
   * @param password - пароль пользователя
   * @return true - пользователь успешно добавлен, false - пользователь с таким именем уже зарегистрирован в системе
   */
  public boolean addUser(String name, String password){
   if(name == null) throw new NullPointerException();
   if(password == null) password = "";
   //Если пользовтель уже зарегистрирован в системе, то завершить выполнение метода
   if(isUser(name)) return false;
   //Получаем корень XML-документа
   Element root = document.getDocumentElement();
   //Создаём элемент пользователь
   Element user = document.createElement(USER);
   user.setAttribute(NAME, name);
   user.setAttribute(PASSWORD, password);
   //Добавляем пользователя к корневому элементу
   root.appendChild(user);
   return true;
  }


  /**
   * Удалить зарегистрированного пользователя из системы
   * @param name - имя пользователя
   * @return true - удаление пользователя прошло успешно, false - пользователь с таким именем не найден в системе
   */
  public boolean removeUser(String name){
    if(name == null) throw new NullPointerException();
    //Получаем корень XML-документа
    Element root = document.getDocumentElement();
    //Проверить, существует ли настройки пользователя с заданным именем в файле
    Element removeUser = findUser(name);
    //Если такого пользователя нет, то выходим из метода
    if(removeUser == null) return false;
    root.removeChild(removeUser);
    return true;
  }

  /**
   * Изменить значение пароля
   * @param name - имя пользователя
   * @param password - новый пароль
   * @return true - значение пароля успешно измененно, false - настройки пользователя с заданным именем не найдены в файле
   */
  public boolean modifyPassword(String name, String password){
    if(name == null) throw new NullPointerException();
    if(password == null) password = ""; 
    //Найти XML-элемент пользователя с заданным именем
    Element user = findUser(name);
    //Если такого пользователя нет, то выходим из системы
    if(user == null) return false;
    //Модифицируем пароль пользователя
    user.setAttribute(PASSWORD, password);
    return true;
  }

  /**
   * Получить пароль пользователя
   * @param name - имя пользователя
   * @return пароль пользователя
   */
  public String getPassword(String name){
   if(name == null) throw new NullPointerException();
   //Найти XML-элемент пользователя с заданным именем
   Element user = findUser(name);
   //Если такого пользователя нет, то выходим из системы
   if(user == null) return null;
   //Ивлекаем пароль пользователя
   String password = user.getAttribute(PASSWORD);
   return password;
  }

  
  /**
   * Экспортировать XML-файл в файл с именем UserOption  
   * @throws java.io.IOException - ошибка преобразования или чтения файла
   */
  public void Export() throws IOException {

  File f = new File(path + fileName);
  try{
  f.createNewFile();
  FileOutputStream ostream = new FileOutputStream(f);

  //Преобразование не выполняющее никаких действий
  Transformer t = TransformerFactory.newInstance().newTransformer();
  t.transform(new DOMSource(document), new StreamResult(ostream));

  }catch(FileNotFoundException fe){
  }catch(TransformerConfigurationException ioe){
    throw new IOException();
  }catch(TransformerException te){
    throw new IOException();
  }

  }

  /**
   * Импорт данных из файла
   * @throws java.io.IOException - ошибка чтения из файла
   * @throws javax.xml.parsers.ParserConfigurationException - ошибка конфигурации XML - парсера - хрен бы знал что делать в таком случае
   * @throws org.xml.sax.SAXException - ошибка SAX - разбора - ну типа формат файла покорёжен
   */
  public void Import() throws IOException, ParserConfigurationException, SAXException{
   File f = new File(path + fileName);
   DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
   DocumentBuilder builder = factory.newDocumentBuilder();
   document = builder.parse(f);
  }

  /**
   *
   * Удалить учётные записи всех юзеров
   */
  public void removeAllUser(){
   Element root = document.getDocumentElement();
   NodeList userList = root.getChildNodes();
   while(userList.getLength() != 0){
    root.removeChild(userList.item(0));
   }
  }

  /**
   * Добавить URL сервера пользователю
   * @param userName - имя пользователя
   * @param serverName - URL сервера
   * @return true - сервер добавлен, false - пользователь не зарегестрирован или сервер с таким именем уже суш
   */
  public boolean addServer(String userName, String serverName){
   if(userName == null || serverName == null) throw new NullPointerException();
   //Получить элемент - юзер
   Element user = findUser(userName);
   //Если пользователь не зарегестрирован завершаем выполнение метода
   if(user == null) return false;
   //Если сервера с таким именем нет в спике у пользователя то добавляем его
   if(findServer(user, serverName)) return false;
   Element server = document.createElement(SERVER);
   server.setAttribute(HOST, serverName);
   user.appendChild(server);
   return true;
  }


  /**
   * Удалить URL сервера пользователя
   * @param userName - имя пользователя
   * @param serverName - URL сервера
   * @return true - сервер удалён, false - - пользователь не зарегестрирован или сервер с таким именем уже не существует
   */
  public boolean removeServer(String userName, String serverName){
   if(userName == null || serverName == null) throw new NullPointerException();
   //Получить элемент - юзер
   Element user = findUser(userName);
   //Если пользователь не зарегестрирован завершаем выполнение метода
   if(user == null) return false;
   //Если сервера с таким именем есть т в спике у пользователя то удаляем его
   Element server = getServer(user, serverName);
   if(server == null) return false;
   user.removeChild(server);
   return true;
  }

  /**
   * Удалить все URL пользователя
   * @param userName - имя пользователя
   * @return true - удаление прошло успешно, false - пользователь не зарегистрирован в системе
   */
  public boolean removeAllServer(String userName){
   if(userName == null) throw new NullPointerException();
   //Получить элемент - юзер
   Element user = findUser(userName);
   //Если пользователь не зарегестрирован завершаем выполнение метода
   if(user == null) return false;
   //Получить список серверов
   NodeList serverList = user.getChildNodes();
   while(serverList.getLength() != 0){
    user.removeChild(serverList.item(0));
   }
   return false;
  }

  /**
   * Проверить есть ли у пользователя, хотя бы один сервер
   * @param userName - имя сервера
   * @return true - есть хотя бы один сервер, false - нет ни одного сервера
   */
  public boolean isServer(String userName){
   if(userName == null) throw new NullPointerException();
   //Получить элемент - юзер
   Element user = findUser(userName);
   //Если пользователь не зарегестрирован завершаем выполнение метода
   if(user == null) return false;
   //Если у пользователя есть хотя бы один сервер то метод выполнен
   NodeList serverList = user.getChildNodes(); 
   for(int i = 0; i < serverList.getLength(); i++){
     if(serverList.item(i) instanceof Element) return true;
   }   
   return false;
  }

  /**
   * Получить списко зарегистрированных в системе пользователей
   * @return список пользователей
   */
  public LinkedList<String> getUserList(){
   LinkedList<String> list = new LinkedList<String>();
   Element root = document.getDocumentElement();
   NodeList userList = root.getChildNodes();
   for(int i = 0; i < userList.getLength(); i++){
    if(userList.item(i) instanceof Element){
     list.add(userList.item(i).getTextContent());
    }
   }
   return list;
  }

  /**
   * Получить список всех сервером зарегистрированного пользователя
   * @param userName - имя пользователя
   * @return список серверов
   */
  public LinkedList<String> getServerList(String userName){
   LinkedList<String> list = new LinkedList<String>();
   if(userName == null) throw new NullPointerException();
   //Получить элемент - юзер
   Element user = findUser(userName);
   //Если пользователь не зарегестрирован завершаем выполнение метода
   if(user == null) return list; 
   NodeList serverList = user.getChildNodes();
   for(int i = 0; i < serverList.getLength(); i++){
    if(serverList.item(i) instanceof Element){
     Element server = (Element)serverList.item(i);
     String host = server.getAttribute(HOST);
     list.add(host);
    }
   }
   return list;
  }

  //-----------------------------------------------------------------------
}
